﻿#region

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
using System.Net;
using BattleNET;
using System.Globalization;
using System.Diagnostics;
#endregion

namespace DayZAntiHax
{
    public class LogFile : Process
    {
        //declarations
        #region
        public int index;
        public List<String> m_Bannable;
        public List<String> m_Fair;
        public string m_sFilterURL;
        public bool m_bFilterUpdate;
        public bool m_bFilterScan;
        public string m_FilterName;
        public string m_LogName;
        public string m_FilterCfgName;
        public int lastScannedIndex;
        public int lastScannedFloodIndex;
        #endregion
        //Object constructor
        public LogFile(int i, string url, bool update, bool scan, string name, string logName, string cfgName)
        {
            index = i;
            m_sFilterURL = url;
            m_bFilterUpdate = update;
            m_bFilterScan = scan;
            m_FilterName = name;
            m_LogName = logName;
            m_FilterCfgName = cfgName;
            lastScannedIndex = 0;
            lastScannedFloodIndex = 0;
        }
        //Filter read function
        public bool registerFilter()
        {
            m_Bannable = new List<String>();
            m_Fair = new List<String>();
            try
            {
                FileInfo file = new FileInfo(this.m_FilterName);
                StreamReader reader = file.OpenText();
                String line;
                int curr = 0;
                string lastBannable="hopethiswillneverbeinfilter";
                while ((line = reader.ReadLine()) != null)
                {
                    curr++;
                    if (line[0] == '5' || line[0] == '7')
                    {
                      //  Console.WriteLine("Found disallowed line! "+line);
                        String[] temp = line.Split(' ');
                        for (int i = 0; i < temp.Length; i++)
                            if (temp[i].Contains('!'))
                            {
                             //   Console.WriteLine("Adding fair " + this.m_FilterName + " " + temp[i].TrimStart('!').TrimStart('=').TrimStart('"').TrimEnd('"'));
                                m_Fair.Add(temp[i].TrimStart('!').TrimStart('=').TrimStart('"').TrimEnd('"'));
                            }
                        if (temp.Length>1)
                        {
                            string bn;
                            if (temp[1] != "")
                               bn  = temp[1].TrimStart('"').TrimEnd('"');
                            else 
                                bn = temp[1];
                            m_Bannable.Add(bn);
                            lastBannable = bn;
                        }
                        else
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                            Console.WriteLine("You have an error in the " + this.m_FilterName + " syntax at line " + curr);
                            Console.WriteLine(line);
                            Console.ForegroundColor = ConsoleColor.Yellow;
                            Console.WriteLine("Press any key to continue...");
                            Console.ReadKey(true);
                            continue;
                        }
                    }
                    else if (line == "//ignore")
                    {
//                        Console.WriteLine("Removing " + lastBannable + " from " + m_FilterName);
                        m_Bannable.Remove(lastBannable);
                    }
                }
                reader.Close();
//                Console.WriteLine("Filter for " + this.m_FilterName + " was registered!");
                return true;
            }
            catch (Exception e)
            {
                if (m_bShouldShowErrorMessage)
                {
                    Console.WriteLine(e+"            Failed to read from " + this.m_FilterName + "!");
                    Console.WriteLine("            Make sure it is located in the same directory as the executable!");
                }
                return false;
            }
        }
        //Parse logs for violations
        public void ParseFilter()
        {
            try
            {
                if (this.m_bFilterScan)
                {
//                    Console.WriteLine("Starting parse "+this.index);
                    // First pass
                    string[] lines = File.ReadAllLines(m_LogName);
                    string line;
                    if (lastScannedIndex != lines.Length - 1 && lastScannedIndex != lines.Length - 61)
                    for(int j=lastScannedIndex;j<lines.Length; j++)
                    {
                        line = lines[j];
                        String[] items = line.Split(' ');

                        bool bannableObjectFound = false;
                        foreach (String item in m_Bannable)
                        {
                            if (line.Contains(item))
                            {
//                                Console.WriteLine("Disallowed cargo found: " + item);
                                bool found = true;
                                foreach (String fairItem in m_Fair)
                                {
                                    if (line.Contains(fairItem))
                                    {
                                        found = false;
                                    }
                                }
                                if (found)
                                {
//                                    Console.WriteLine("Disallowed cargo was not found in allowdz: " + item);
                                    bannableObjectFound = true;
                                    break;
                                }
                            }
                        }

                        if (bannableObjectFound)
                        {
                            for (int i = 0; i < items.Length; i++)
                            //foreach (String item in items)
                            {
                                if(Process.m_banType==0 || Process.m_banType==2)
                                if (items[i].Length == 32)
                                {
                                    Guid.Parse(items[i]);
                                    string banexpl;
                                    if(banMessage.Split('%').Length==2)
                                        banexpl = banMessage.Split('%')[0]+this.m_FilterCfgName+banMessage.Split('%')[1];
                                    else banexpl = banMessage;
                                    if (Process.m_GuidsToBeBanned.Contains(new String[5] { items[i], banexpl, items[0], items[1], this.m_LogName }))
                                    {
//                                        Console.WriteLine("Guid is already added to banlist");
                                        continue;
                                    }
                                    else
                                    {
                                        Process.m_GuidsToBeBanned.Add(new String[5] { items[i], banexpl, items[0], items[1], this.m_LogName });
//                                                                             Console.WriteLine("Added GUID " + items[i]);
                                        Process.m_BanExplanations.Add("line: " + j+" "+line);
                                    }
                                }
                                if (Process.m_banType == 1 || Process.m_banType == 2)
                                {
                                    IPAddress IPtoBan;
                                    String [] address= items[i].Split('.');
                                    if (address.Length ==4 && IPAddress.TryParse(address[0].TrimStart('(')+"."+address[1]+"."+address[2]+"."+address[3].Split(':')[0], out IPtoBan))
                                    {
                                        string iptoban = address[0].TrimStart('(') + "." + address[1] + "." + address[2] + "." + address[3].Split(':')[0];
                                        string banexpl;
                                        if (banMessage.Split('%').Length == 2)
                                            banexpl = banMessage.Split('%')[0] + this.m_FilterCfgName + banMessage.Split('%')[1];
                                        else banexpl = banMessage;
                                        if (Process.m_IPsToBeBanned.Contains(new String[5] { iptoban, banexpl, items[0], items[1], this.m_LogName }))
                                        {
                                            //                                        Console.WriteLine("Guid is already added to banlist");
                                            continue;
                                        }
                                        else
                                        {
                                            Process.m_IPsToBeBanned.Add(new String[5] { iptoban, banexpl, items[0], items[1], this.m_LogName });
                                        }
                                    }
                                }
                            }
                        }
                        if (lines.Length > 61)
                            this.lastScannedIndex = lines.Length - 61;
                        else if (lines.Length != 0) this.lastScannedIndex = lines.Length - 1;   
                    }
//                    else Console.WriteLine("Skipping "+this.m_FilterName+" Scan..(not enough new info for scanning)");
                }
            }
            catch (Exception)
            {
                if (m_bShouldShowErrorMessage)
                {
                    Console.WriteLine("     The log for "+this.m_FilterName +" was not found, but you've set it's scan ON.");
                    Console.WriteLine("     Make sure the executable is located in your server's '/BattlEye' directory!");
                }
            }
        }
        //Check logs for flood (more then 30 objects in a row from the same user at the same timestamp)
        public void checkForFlood()
        {
            try
            {
                string[] lines = File.ReadAllLines(m_LogName);
                string line;
                int iNumTimesLastDateTimeGUIDAppearsConsecutively = 1;
                String lastScannedLine = lines[0];
                String[] items = lastScannedLine.Split(' ');
                lastScannedLine = items[0] + items[1] + items[items.Length - 5];
                if (lastScannedFloodIndex != lines.Length - 1 && lastScannedFloodIndex != lines.Length - 61)
                {
                    for (int j = lastScannedFloodIndex; j < lines.Length; j++)
                    {
                        line = lines[j];
                        items = line.Split(' ');
                        String lastLine;
                        lastLine = items[0] + items[1] + items[items.Length - 5];
                        if (lastLine == lastScannedLine)
                            iNumTimesLastDateTimeGUIDAppearsConsecutively++;
                        else
                        {
                            iNumTimesLastDateTimeGUIDAppearsConsecutively = 1;
                            lastScannedLine = lastLine;
                        }
                        if (iNumTimesLastDateTimeGUIDAppearsConsecutively >= 30)
                        {
                            if (Process.m_banType == 0 || Process.m_banType == 2)
                            {
                                if (m_GuidsToBeBanned.Contains(new String[5] { items[items.Length - 5], "Object Access Flooding", items[0], items[1], m_LogName }))
                                    continue;
                                Process.m_BanExplanations.Add("LINES: "+(j-29)+"--"+j);
                                m_GuidsToBeBanned.Add(new String[5] { items[items.Length - 5], "Object Access Flooding", items[0], items[1], m_LogName });
                            }
                            if (Process.m_banType == 1 || Process.m_banType == 2)
                            {
                                if (m_IPsToBeBanned.Contains(new String[5] { items[items.Length - 6].Trim('(').Split(':')[0], "Object Access Flooding", items[0], items[1], m_LogName }))
                                    continue;
                                m_IPsToBeBanned.Add(new String[5] { items[items.Length - 6].Trim('(').Split(':')[0], "Object Access Flooding", items[0], items[1], m_LogName });
                            } 
                            iNumTimesLastDateTimeGUIDAppearsConsecutively = 1;
                        }
                    }
                    if (lines.Length > 61)
                        this.lastScannedFloodIndex = lines.Length - 61;
                    else if (lines.Length != 0) this.lastScannedFloodIndex = lines.Length - 1;
                }
                //                else Console.WriteLine("Skipping " + this.m_FilterName + "Flood Scan..(not enough new info for scanning)");
                lines = null;
            }
            catch (Exception)
            {
                if (m_bShouldShowErrorMessage)
                {
                    Console.WriteLine("     The log for " + this.m_FilterName + " was not found, but you've set it's scan ON.");
                    Console.WriteLine("     Make sure the executable is located in your server's '/BattlEye' directory!");
                }
            }
        }
    }
}
